﻿using System;
using System.Drawing;

namespace RibbonControler
{
    public class HSLColor
    {
        // Private data members below are on scale 0-1
        // They are scaled for use externally based on scale
        private double hue = 0;
        private double saturation = 1.0;
        private double luminosity = 1.0;

        public double Hue
        {
            get { return hue; }
            set { hue = (value > 1.0) ? 1.0 : ((value < 0) ? 0 : value); }
        }
        public double Saturation
        {
            get { return saturation; }
            set { saturation = (value > 1.0) ? 1.0 : ((value < 0) ? 0 : value); }
        }
        public double Luminosity
        {
            get { return luminosity; }
            set { luminosity = (value > 1.0) ? 1.0 : ((value < 0) ? 0 : value); }
        }


        public override string ToString()
        {
            return String.Format("H: {0:#0.##} S: {1:#0.##} L: {2:#0.##}", Hue, Saturation, Luminosity);
        }

        public string ToRGBString()
        {
            Color color = (Color)this;
            return String.Format("R: {0:#0.##} G: {1:#0.##} B: {2:#0.##}", color.R, color.G, color.B);
        }

        #region Casts to/from System.Drawing.Color
        
        public static implicit operator Color(HSLColor hslColor)
        {
            double v;
            double r, g, b;

            double horg = hslColor.hue;
            r = hslColor.luminosity;   // default to gray
            g = hslColor.luminosity;
            b = hslColor.luminosity;
            v = (hslColor.luminosity <= 0.5) ? (hslColor.luminosity * (1.0 + hslColor.saturation)) : (hslColor.luminosity + hslColor.saturation - hslColor.luminosity * hslColor.saturation);
            if (v > 0)
            {
                double m;
                double sv;
                int sextant;
                double fract, vsf, mid1, mid2;

                m = hslColor.luminosity + hslColor.luminosity - v;
                sv = (v - m) / v;
                hslColor.hue *= 6.0;
                sextant = (int)hslColor.hue;
                fract = hslColor.hue - sextant;
                vsf = v * sv * fract;
                mid1 = m + vsf;
                mid2 = v - vsf;
                switch (sextant)
                {
                    case 0:
                    case 6:
                        r = v;
                        g = mid1;
                        b = m;
                        break;
                    case 1:
                        r = mid2;
                        g = v;
                        b = m;
                        break;
                    case 2:
                        r = m;
                        g = v;
                        b = mid1;
                        break;
                    case 3:
                        r = m;
                        g = mid2;
                        b = v;
                        break;
                    case 4:
                        r = mid1;
                        g = m;
                        b = v;
                        break;
                    case 5:
                        r = v;
                        g = m;
                        b = mid2;
                        break;
                }
            }

            r = Convert.ToByte(r * 255.0f);
            g = Convert.ToByte(g * 255.0f);
            b = Convert.ToByte(b * 255.0f);

            hslColor.hue = horg;
            return Color.FromArgb((int)r, (int)g, (int)b);
        }

       

        public static implicit operator HSLColor(Color color)
        {
            double h = 0, s = 0, l = 0;

            double r = color.R / 255.0;
            double g = color.G / 255.0;
            double b = color.B / 255.0;
            double v;
            double m;
            double vm;
            double r2, g2, b2;

            h = 0; // default to black
            s = 0;
            l = 0;
            v = Math.Max(r, g);
            v = Math.Max(v, b);
            m = Math.Min(r, g);
            m = Math.Min(m, b);
            l = (m + v) / 2.0;
            HSLColor hslColor = new HSLColor();
            if (l <= 0.0)
            {
                hslColor.hue = h;
                hslColor.saturation = s;
                hslColor.luminosity = l;
                return hslColor;
            }
            vm = v - m;
            s = vm;
            if (s > 0.0)
            {
                s /= (l <= 0.5) ? (v + m) : (2.0 - v - m);
            }
            else
            {
                hslColor.hue = h;
                hslColor.saturation = s;
                hslColor.luminosity = l;
                return hslColor;
            }
            r2 = (v - r) / vm;
            g2 = (v - g) / vm;
            b2 = (v - b) / vm;
            if (r == v)
            {
                h = (g == m ? 5.0 + b2 : 1.0 - g2);
            }
            else if (g == v)
            {
                h = (b == m ? 1.0 + r2 : 3.0 - b2);
            }
            else
            {
                h = (r == m ? 3.0 + g2 : 5.0 - r2);
            }
            h /= 6.0;

            hslColor.hue = h;
            hslColor.saturation = s;
            hslColor.luminosity = l;
            return hslColor;
        }
        #endregion

        

        public HSLColor() { }

        public HSLColor(double hue, double saturation, double luminosity)
        {
            this.Hue = hue;
            this.Saturation = saturation;
            this.Luminosity = luminosity;
        }


    }
}
